
/**  
* @Title: PayUtil.java
* @Package com.red.util
* @Description: 
* @author likai
* @date 2018年1月4日
* @version V1.0  
*/

package com.third.utils.pay;

import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.third.base.ali.AliPayInWxUtil;
import com.third.base.ali.AlipayParam;
import com.third.base.wx.UnifiedorderResult;
import com.third.utils.ali.AliPayUtil;
import com.third.utils.ali.AlipayConfig;
import com.third.utils.wx.WxPayConfig;
import com.third.utils.wx.WxPayUtil;
import com.utils.date.CalendarUtil;
import com.utils.date.DateUtil;

/**
 * @ClassName: PayUtil
 * @Description:支付工具
 * @author likai
 * @date 2018年1月4日
 *
 */
public class PayUtil{
	public static Logger log = LoggerFactory.getLogger(PayUtil.class);
	private static PayUtil payUtil=new PayUtil();
	private static WxPay wxPay;
	private static AliPay aliPay;

	
	private PayUtil() {
		super();
		
	}
	//微信支付
	public static WxPay wxPayUtil(WxPayConfig wxConfig) {
		if (wxPay==null) {
			wxPay=payUtil.new WxPay(wxConfig);
		}
		return  wxPay;
	}
	//支付宝支付
	public static AliPay aliPayUtil(AlipayConfig aliConfig) {
		if (aliPay == null) {
			aliPay = payUtil.new AliPay(aliConfig);
		}
		return aliPay;
	}

	public class WxPay{
		
		private WxPayConfig wxPayConfig;// 微信支付配置

		
		
		private WxPay(WxPayConfig wxPayConfig) {
			super();
			this.wxPayConfig = wxPayConfig;
		}

		/*
		 * @Description: 微信支付（包含所有类型支付）
		 * 
		 * money：金额 必传 (单位元)
		 * wxOpenId：付款人openId 必传 
		 * tradeNo：平台生成的交易号 必传 
		 * clientIp：支付用户的客户端ip 必传 
		 * payType：支付类型 WXPayConfig 必传 
		 * attach：附加参数，回掉时传回 非必传 
		 * body：交易描述 非必传
		 */

		@SuppressWarnings({ "deprecation" })
		public UnifiedorderResult wxPay(BigDecimal money, String wxOpenId, String tradeNo, String clientIp, String payType,
				String attach, String body) throws Exception {
			Map<String, String> reqData = new HashMap<>();
			reqData.put("trade_type", payType);
			reqData.put("openid", wxOpenId);
			reqData.put("attach", attach);
			reqData.put("out_trade_no", tradeNo);
			reqData.put("body", body);
			money = money.multiply(new BigDecimal(100));// 微信支付单位为分
			reqData.put("total_fee", String.valueOf(money.intValue()));
			//reqData.put("total_fee", "1");
			reqData.put("spbill_create_ip", clientIp);
			reqData.put("time_expire",
					DateUtil.COMPAT_FULL.getDateText(CalendarUtil.minHeadDate(CalendarUtil.getBjDate(), 2)));// 有效时间2分钟
			WxPayUtil wxpay = WxPayUtil.create(wxPayConfig);
			Map<String, String> payResult = wxpay.unifiedOrder(reqData);

			if (payResult == null) {
				// 支付失败
				return null;
			} else {
				UnifiedorderResult unifiedorderResult = new UnifiedorderResult();
				unifiedorderResult.setAppId(payResult.get("appid"));
				unifiedorderResult.setMchId(payResult.get("mch_id"));
				unifiedorderResult.setTradeType(payResult.get("trade_type"));
				unifiedorderResult.setPrepayId(payResult.get("prepay_id"));
				unifiedorderResult.setNonceStr(payResult.get("nonce_str"));
				unifiedorderResult.setReturnUrl(wxPayConfig.getReturnUrl());
				// 支付成功
				if (payType.equals(WxPayConfig.MWEB)) {
					String mweb_url = payResult.get("mweb_url");
					// h5支付,添加支付完成跳转页面
					mweb_url = mweb_url + "&redirect_url=" + URLDecoder.decode(wxPayConfig.getReturnUrl());// 支付完成跳转页面
					unifiedorderResult.setMweb_url(mweb_url);
					;
				} else if (payType.equals(WxPayConfig.JSAPI)) {
					// jsapi支付,生成jsapi签名
					unifiedorderResult.setPackageId("prepay_id=" + unifiedorderResult.getPrepayId());
					unifiedorderResult.setTimeStamp(String.valueOf(CalendarUtil.getShortTime()));
					unifiedorderResult.setSignType("MD5");
					// 生成签名
					Map<String, String> param = new HashMap<>();
					param.put("appId", unifiedorderResult.getAppId());
					param.put("nonceStr", unifiedorderResult.getNonceStr());
					param.put("package", unifiedorderResult.getPackageId());
					param.put("signType", unifiedorderResult.getSignType());
					param.put("timeStamp", unifiedorderResult.getTimeStamp());
					String paySign = wxpay.generateSignature(param);
					unifiedorderResult.setPaySign(paySign);
				} else if (payType.equals(WxPayConfig.NATIVE)) {
					// 原生扫码支付
					unifiedorderResult.setCode_url(payResult.get("code_url"));
				}
				return unifiedorderResult;
			}

		}
		
		/*
		 * @Description: 微信全额退款
		 * 
		 * @return
		 * 
		 * @see com.rshop.service.OrderService#orderPay(int, java.lang.String,
		 * java.lang.String)
		 */

		public void wxFullRefund(String out_trade_no, BigDecimal payMoney, String reason) {
			Map<String, String> reqData = new HashMap<>();
			reqData.put("out_trade_no", out_trade_no);// 平台订单号
			reqData.put("refund_desc", reason);// 退款原因
			reqData.put("total_fee", String.valueOf(
					new BigDecimal(Double.toString(payMoney.doubleValue())).multiply(new BigDecimal(100)).intValue()));// 支付金额
			reqData.put("refund_fee", String.valueOf(payMoney.multiply(new BigDecimal(100)).intValue()));// 退款金额
			// 全额退款，只退款一次，out_refund_no设置唯一不变
			reqData.put("out_refund_no", out_trade_no);// 商户退款单号商户系统内部的退款单号，商户系统内部唯一，只能是数字、大小写字母_-|*@
														// ，同一退款单号多次请求只退一笔。
			try {
				WxPayUtil wxpay = WxPayUtil.create(wxPayConfig);
				wxpay.refund(reqData);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		/*
		 * @Description:微信商户转账给用户 
		 * 
		 * @return
		 * 
		 */

		public boolean wxTransfers(String out_trade_no, String wxOpenId,BigDecimal transMoney,String desc, String clientIp) throws Exception {
			Map<String, String> reqData=new HashMap<>();
			reqData.put("partner_trade_no", out_trade_no);//平台交易单号
			reqData.put("openid", wxOpenId);//商户appid下，某用户的openid
			reqData.put("desc", desc);//企业付款描述信息
			transMoney=transMoney.multiply(new BigDecimal("100"));//微信支付单位为分
			reqData.put("amount",String.valueOf(transMoney.intValue()));
			reqData.put("spbill_create_ip",clientIp);
			Map<String, String> payResult=WxPayUtil.create(wxPayConfig).transfers(reqData);
			if (payResult!=null&&payResult.get("return_code").equals("SUCCESS")&&payResult.get("result_code").equals("SUCCESS")) {
				return true;
			}else {
				log.error(payResult+"");
				return false;
			}
		}
	}
	
	public class AliPay{
		
		private AlipayConfig aliConfig;// 支付宝配置
		

		private AliPay(AlipayConfig aliConfig) {
			super();
			this.aliConfig = aliConfig;
		}

		/*
		 * @Description: 支付宝手机网站支付（调起手机支付宝或h5）
		 * 
		 * money：金额 必传 (单位元)
		 * tradeNo：平台生成的交易号 必传 
		 * attach：附加参数，回掉时传回 非必传
		 * body：交易描述 非必传
		 */

		@SuppressWarnings({ "deprecation" })
		public AlipayTradeWapPayResponse aliWapPay(BigDecimal money, String tradeNo, String attach, String body)
				throws Exception {
			// 支付宝手机网页支付
			AlipayParam alipayParam = new AlipayParam();
			alipayParam.setOut_trade_no(tradeNo);
			alipayParam.setSubject(body);
			alipayParam.setTotal_amount(Double.toString(money.doubleValue()));
			alipayParam.setPassback_params(URLEncoder.encode(attach));// 订单类型，回掉时传回
			// alipayParam.setTimeout_express("90m");//订单失效时间
			AliPayUtil aliPay = AliPayUtil.create(aliConfig);
			AlipayTradeWapPayResponse payResult = aliPay.wapPay(alipayParam);
			if (payResult != null) {
				// 成功,处理支付返回页面，直接将页面输出到浏览器，支付宝将自动检测使用h5还是调用app支付
				payResult.setBody(AliPayInWxUtil.payFormStart + payResult.getBody() + AliPayInWxUtil.payFormEnd);
				return payResult;
			} else {
				return null;
			}
		}

		/*
		 * @Description: 支付宝PC网站支付
		 * 
		 * money：金额 必传 tradeNo：平台生成的交易号 必传 attach：附加参数，回掉时传回 非必传 body：交易描述 非必传
		 */

		@SuppressWarnings({ "deprecation" })
		public AlipayTradePagePayResponse aliPcPay(BigDecimal money, String tradeNo, String attach, String body)
				throws Exception {
			// 支付宝手机网页支付
			AlipayParam alipayParam = new AlipayParam();
			alipayParam.setOut_trade_no(tradeNo);
			alipayParam.setSubject(body);
			alipayParam.setTotal_amount(Double.toString(money.doubleValue()));
			alipayParam.setPassback_params(URLEncoder.encode(attach));// 订单类型，回掉时传回
			// alipayParam.setTimeout_express("90m");//订单失效时间
			AliPayUtil aliPay = AliPayUtil.create(aliConfig);
			AlipayTradePagePayResponse payResult = aliPay.pcPay(alipayParam);
			if (payResult != null) {
				// 成功,处理支付返回页面，直接将页面输出到浏览器，支付宝将自动检测使用h5还是调用app支付
				payResult.setBody(AliPayInWxUtil.payFormStart + payResult.getBody() + AliPayInWxUtil.payFormEnd);
				return payResult;
			} else {
				return null;
			}
		}

		
		/*
		 * @Description: 支付宝商户转账给用户
		 * 
		 * @param:payerName:付款方名称
		 * 		  desc：备注
		 * @return
		 * 
		 */

		public boolean aliTransfers(String out_trade_no, String aliAccount,BigDecimal transMoney,String payerName,String desc) throws Exception {
			AlipayParam alipayParam = new AlipayParam();
			alipayParam.setOut_biz_no(out_trade_no);
			alipayParam.setPayee_type("ALIPAY_LOGONID");
			alipayParam.setPayee_account(aliAccount);// 收款方账户
			alipayParam.setAmount(String.valueOf(transMoney.doubleValue()));
			alipayParam.setPayer_show_name(payerName);
			alipayParam.setRemark(desc);
			AliPayUtil aliPay = AliPayUtil.create(aliConfig);
			AlipayFundTransToaccountTransferResponse response=aliPay.transfer(alipayParam);
			if (response.isSuccess()) {
				//提现成功，修改用户账户余额
				return true;
				
			} else {
				if (response.getSubCode().equals("PAYEE_NOT_EXIST")) {
					throw new Exception("支付宝账号不存在！");
				}else {				
					throw new Exception("支付宝提现失败！");
				}
			}
		}
		
	}

	
	
}
